// Copyright (c) Microsoft Corporation.  All rights reserved.
#pragma once

//
// SCF Parser
//
// It consumes SCF XML and generates the CScfElement tree using SAX parser in MSXML.
//

HRESULT GetSAXAttributeUInt(LPCWSTR pwszAttrName, ISAXAttributes *pAttributes, UINT *puiVal, BOOL bRequired, int base = 10);
HRESULT GetSAXAttributeBool(LPCWSTR pwszAttrName, ISAXAttributes *pAttributes, BOOL *pBool, BOOL bRequired);
HRESULT GetSAXAttributeString(LPCWSTR pwszAttrName, ISAXAttributes *pAttributes, wstring& wstr, BOOL bRequired);
HRESULT GetSAXAttributeRgb(ISAXAttributes *pAttributes, COLORREF *pRgb, BOOL bRequired);

struct SCF_ELEMENT_INFO
{
    LPCWSTR pwszName;
    SCF_ELEMENT_TYPE ElemType;
    SCF_ELEMENT_TYPE *pChildElems;
};

class CScfParserElementStackItem
{
public:
    CScfParserElementStackItem() {}
    
    CScfParserElementStackItem(SCF_ELEMENT_INFO* pElemInfo, CScfElement* pElem)
    : m_pElemInfo(pElemInfo), m_pElem(pElem)
    {}

    SCF_ELEMENT_INFO* m_pElemInfo;
    CScfElement* m_pElem;
};

class CScfParser :
    public CComObjectRoot,
    public ISAXContentHandler,
    public ISAXErrorHandler
{
public:
    static HRESULT CScfParser::Parse(LPCWSTR pwszContentXml, CScfContentBase** ppParsedContent);
    static HRESULT CScfParser::Parse(HGLOBAL hGlobal, CScfContentBase** ppParsedContent);
    static HRESULT CScfParser::Parse(VARIANT *pvarXml, CScfContentBase** ppParsedContent);
    
    CScfParser()
    {
        m_pContentElement = NULL;

        m_pCurrentElemInfo = NULL;
        m_pCurrentElem = NULL;
        
        m_pTxtElement = NULL;
        m_pItemElement = NULL;
        m_rgbClr = 0;
        m_nClrStartPos = -1;
        m_nEmStartPos = -1;

        m_nErrorLine = 0;
        m_nErrorColumn = 0;
        m_hrErrorCode = S_OK;
    }

    ~CScfParser()
    {
    }
    
    BEGIN_COM_MAP(CScfParser)
        COM_INTERFACE_ENTRY(ISAXContentHandler)
        COM_INTERFACE_ENTRY(ISAXErrorHandler)
    END_COM_MAP()   

    //
    // ISAXContentHandler
    //
    HRESULT STDMETHODCALLTYPE putDocumentLocator( 
        /* [in] */ ISAXLocator *pLocator);
    
        
    HRESULT STDMETHODCALLTYPE startDocument();
    
    HRESULT STDMETHODCALLTYPE endDocument();
    
    HRESULT STDMETHODCALLTYPE startPrefixMapping( 
        /* [in] */ const wchar_t* pwchPrefix,
        /* [in] */ int cchPrefix,
        /* [in] */ const wchar_t* pwchUri,
        /* [in] */ int cchUri);
    

    HRESULT STDMETHODCALLTYPE endPrefixMapping( 
        /* [in] */ const wchar_t* pwchPrefix,
        /* [in] */ int cchPrefix);
    
    
    HRESULT STDMETHODCALLTYPE startElement( 
        /* [in] */ const wchar_t* pwchNamespaceUri,
        /* [in] */ int cchNamespaceUri,
        /* [in] */ const wchar_t* pwchLocalName,
        /* [in] */ int cchLocalName,
        /* [in] */ const wchar_t* pwchQName,
        /* [in] */ int cchQName,
        /* [in] */ ISAXAttributes* pAttributes);

    HRESULT STDMETHODCALLTYPE endElement( 
        /* [in] */ const wchar_t* pwchNamespaceUri,
        /* [in] */ int cchNamespaceUri,
        /* [in] */ const wchar_t* pwchLocalName,
        /* [in] */ int cchLocalName,
        /* [in] */ const wchar_t* pwchQName,
        /* [in] */ int cchQName);

    HRESULT STDMETHODCALLTYPE characters( 
        /* [in] */ const wchar_t* pwchChars,
        /* [in] */ int cchChars);

    HRESULT STDMETHODCALLTYPE ignorableWhitespace( 
        /* [in] */ const wchar_t* pwchChars,
        /* [in] */ int cchChars);
    

    HRESULT STDMETHODCALLTYPE processingInstruction( 
        /* [in] */ const wchar_t* pwchTarget,
        /* [in] */ int cchTarget,
        /* [in] */ const wchar_t* pwchData,
        /* [in] */ int cchData);
    

    HRESULT STDMETHODCALLTYPE skippedEntity( 
        /* [in] */ const wchar_t* pwchName,
        /* [in] */ int cchName);
    
    //
    // ISAXErrorHandler
    //
    HRESULT STDMETHODCALLTYPE error(
       /* [in] */ ISAXLocator* pLocator, 
       /* [in] */ const wchar_t* pwchErrorMessage,
       /* [in] */ HRESULT hrErrorCode);

    HRESULT STDMETHODCALLTYPE fatalError(
        /* [in] */ ISAXLocator* pLocator, 
        /* [in] */ const wchar_t* pwchErrorMessage,
        /* [in] */ HRESULT hrErrorCode);

    HRESULT STDMETHODCALLTYPE ignorableWarning(
        /* [in] */ ISAXLocator* pLocator, 
        /* [in] */ const wchar_t* pwchErrorMessage,
        /* [in] */ HRESULT hrErrorCode);

private:
    SCF_ELEMENT_INFO* _LookupSupportedElement(const wchar_t *pwchName, int cchName);
    BOOL _IsValidChildElement(SCF_ELEMENT_INFO *pParent, SCF_ELEMENT_INFO *pChild);

    // state and temp variables for "txt"
    CScfTxtElement* m_pTxtElement;
    CScfItemElement* m_pItemElement;
    COLORREF m_rgbClr;
    int m_nClrStartPos;
    int m_nEmStartPos;

    // parser context
    SCF_ELEMENT_INFO* m_pCurrentElemInfo;
    CScfElement* m_pCurrentElem;
    list<CScfParserElementStackItem> m_ElemStack;

    int m_nErrorLine;
    int m_nErrorColumn;
    HRESULT m_hrErrorCode;

public:
    // parsed result is stored in this. it's actually <content>, <menu> or <dialog> element
    CScfContentBase* m_pContentElement;
};
